<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>美食点评 - 预签名URL上传演示</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
      margin: 20px;
      background-color: #f4f4f9;
      color: #333;
    }
    .container {
      max-width: 600px;
      margin: 20px auto;
      padding: 25px;
      background-color: #fff;
      border-radius: 8px;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    }
    .form-group {
      margin-bottom: 18px;
    }
    label {
      display: block;
      margin-bottom: 6px;
      font-weight: bold;
      color: #555;
    }
    input[type="text"],
    input[type="number"],
    textarea,
    input[type="file"] {
      width: 100%;
      padding: 10px;
      border: 1px solid #ccc;
      border-radius: 4px;
      box-sizing: border-box; /* Important for consistent sizing */
      font-size: 1rem;
    }
    textarea {
      resize: vertical; /* Allow vertical resizing */
      min-height: 80px;
    }
    input[type="file"] {
        padding: 5px; /* Adjust padding for file input */
    }
    button {
      display: inline-block;
      padding: 12px 20px;
      background-color: #007bff; /* Blue */
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      font-size: 1rem;
      transition: background-color 0.3s ease;
    }
    button:hover {
      background-color: #0056b3; /* Darker blue */
    }
    button:disabled {
        background-color: #cccccc;
        cursor: not-allowed;
    }
    .status {
      margin-top: 20px;
      padding: 12px;
      border-radius: 4px;
      font-size: 0.95rem;
    }
    .status.info {
        background-color: #e2f3ff; /* Light blue for info */
        color: #004085;
        border: 1px solid #b8daff;
    }
     .status.success {
        background-color: #d4edda; /* Light green for success */
        color: #155724;
        border: 1px solid #c3e6cb;
    }
    .status.error {
        background-color: #f8d7da; /* Light red for error */
        color: #721c24;
        border: 1px solid #f5c6cb;
    }
    /* 图片预览样式 */
    .image-preview-container {
      display: flex;
      flex-wrap: wrap;
      gap: 10px;
      margin-top: 10px;
    }
    .image-preview {
      position: relative;
      width: 100px;
      height: 100px;
      border-radius: 4px;
      overflow: hidden;
      background-color: #f0f0f0;
    }
    .image-preview img {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
    .image-remove {
      position: absolute;
      top: 5px;
      right: 5px;
      background-color: rgba(255, 255, 255, 0.8);
      color: #ff4d4f;
      border-radius: 50%;
      width: 20px;
      height: 20px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      font-size: 14px;
      font-weight: bold;
      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
    }
    /* 进度条样式 */
    .progress-container {
      height: 5px;
      background-color: #f0f0f0;
      border-radius: 3px;
      margin-top: 5px;
      overflow: hidden;
    }
    .progress-bar {
      height: 100%;
      background-color: #007bff;
      width: 0%;
      transition: width 0.3s ease;
    }
    /* Basic responsive adjustments */
    @media (max-width: 600px) {
        .container {
            margin: 10px;
            padding: 15px;
        }
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>📝 美食点评 - 预签名URL上传模式</h1>

    <div class="form-group">
      <label for="userId">学号：</label>
      <input type="text" id="userId" placeholder="请输入你的学号" required>
    </div>

    <div class="form-group">
      <label for="userName">姓名/昵称：</label>
      <input type="text" id="userName" placeholder="（选填）">
    </div>

    <div class="form-group">
      <label for="restaurantName">餐厅名称：</label>
      <input type="text" id="restaurantName" placeholder="例如：东区均园食堂二楼" required>
    </div>

    <div class="form-group">
      <label for="restaurantLocation">餐厅位置：</label>
      <input type="text" id="restaurantLocation" placeholder="例如：靠近图书馆" required>
    </div>

    <div class="form-group">
      <label for="dishName">推荐菜品：</label>
      <input type="text" id="dishName" placeholder="（选填）例如：麻辣香锅">
    </div>

    <div class="form-group">
      <label for="rating">评分 (1-5)：</label>
      <input type="number" id="rating" min="1" max="5" placeholder="输入1到5的整数" required>
    </div>

    <div class="form-group">
      <label for="reviewText">评价内容：</label>
      <textarea id="reviewText" rows="4" placeholder="分享你的美食体验..." required></textarea>
    </div>

    <div class="form-group">
      <label for="images">上传图片：</label>
      <input type="file" id="images" multiple accept="image/jpeg, image/png, image/gif">
      <div id="imagePreviewContainer" class="image-preview-container"></div>
    </div>

    <button id="submitBtn">🚀 提交评价</button>

    <div class="status" id="status">请填写信息并提交</div>
  </div>

  <script>
    // 文件上传函数
    async function uploadFile(file) {
      // 获取预签名URL
      const response = await fetch(`/api/upload-url?filename=${encodeURIComponent(file.name)}&contentType=${file.type}`);
      
      if (!response.ok) {
        throw new Error(`获取上传URL失败: ${response.statusText}`);
      }
      
      const { uploadUrl, fileKey } = await response.json();
      
      // 使用预签名URL上传文件
      const uploadResponse = await fetch(uploadUrl, {
        method: 'PUT',
        headers: {
          'Content-Type': file.type
        },
        body: file
      });
      
      if (!uploadResponse.ok) {
        throw new Error(`上传失败: ${uploadResponse.statusText}`);
      }
      
      return { fileKey, url: uploadUrl.split('?')[0] }; // 返回上传后的文件URL
    }

    // 示例：前端文件上传组件
async function handleFileUpload(file) {
  try {
    // 1. 获取预签名URL
    const response = await fetch('/api/upload-url', {
      method: 'GET',
      headers: { 'Content-Type': 'application/json' },
      params: {
        filename: file.name,
        contentType: file.type // 必须与后端ALLOWED_MIME_TYPES一致
      }
    });

    if (!response.ok) {
      throw new Error(`获取上传URL失败: ${response.statusText}`);
    }

    const { uploadUrl } = await response.json();
    console.log('获取预签名URL成功:', uploadUrl);

    // 2. 上传文件到OSS
    const uploadResponse = await fetch(uploadUrl, {
      method: 'PUT',
      headers: {
        'Content-Type': file.type // 必须与预签名URL中的Content-Type一致
      },
      body: file // 直接上传File对象
    });

    if (!uploadResponse.ok) {
      throw new Error(`上传失败: ${uploadResponse.statusText}`);
    }

    console.log('文件上传成功');
    // 3. 上传成功后，调用保存评价的API
    // ...
  } catch (error) {
    console.error('上传过程出错:', error);
    alert(`上传失败: ${error.message}`);
  }
}

    // DOM元素
    const submitBtn = document.getElementById('submitBtn');
    const statusElement = document.getElementById('status');
    const fileInput = document.getElementById('images');
    const imagePreviewContainer = document.getElementById('imagePreviewContainer');

    // --- 配置 ---
    //  重要：确保这个地址与你后端 API 运行的地址一致 
    const API_BASE_URL = 'http://192.168.147.128:3000';
    // -------------

    // 更新状态显示
    function updateStatus(message, type = 'info') {
        statusElement.textContent = message;
        statusElement.className = `status ${type}`;
        console.log(`[${type.toUpperCase()}] ${message}`);
    }

    // 创建图片预览
    function createImagePreview(file) {
      const preview = document.createElement('div');
      preview.className = 'image-preview';
      
      const img = document.createElement('img');
      img.src = URL.createObjectURL(file);
      img.alt = file.name;
      
      const removeBtn = document.createElement('div');
      removeBtn.className = 'image-remove';
      removeBtn.innerHTML = '×';
      removeBtn.onclick = function() {
        preview.remove();
        // 从文件列表中移除
        const dt = new DataTransfer();
        const files = Array.from(fileInput.files).filter(f => f !== file);
        files.forEach(f => dt.items.add(f));
        fileInput.files = dt.files;
      };
      
      preview.appendChild(img);
      preview.appendChild(removeBtn);
      imagePreviewContainer.appendChild(preview);
    }

    // 监听文件选择
    fileInput.addEventListener('change', function() {
      // 清除现有预览
      imagePreviewContainer.innerHTML = '';
      
      // 创建新预览
      for (let i = 0; i < this.files.length; i++) {
        createImagePreview(this.files[i]);
      }
    });

    // 提交按钮点击事件
    submitBtn.addEventListener('click', async function() {
      // 禁用按钮防止重复提交
      submitBtn.disabled = true;
      updateStatus('⏳ 正在处理，请稍候...', 'info');

      try {
        // 1. 收集表单数据
        const userId = document.getElementById('userId').value.trim();
        const userName = document.getElementById('userName').value.trim();
        const restaurantName = document.getElementById('restaurantName').value.trim();
        const restaurantLocation = document.getElementById('restaurantLocation').value.trim();
        const dishName = document.getElementById('dishName').value.trim();
        const rating = document.getElementById('rating').value;
        const reviewText = document.getElementById('reviewText').value.trim();

        // 2. 验证必填字段
        if (!userId || !restaurantName || !restaurantLocation || !rating || !reviewText) {
          updateStatus('⚠️ 请填写所有必填字段 (学号, 餐厅名, 位置, 评分, 内容)', 'error');
          submitBtn.disabled = false; // 重新启用按钮
          return;
        }
        
        const ratingInt = parseInt(rating);
        if (isNaN(ratingInt) || ratingInt < 1 || ratingInt > 5) {
             updateStatus('⚠️ 评分必须是 1 到 5 之间的整数', 'error');
             submitBtn.disabled = false;
             return;
        }

        // 3. 上传图片（如果有选择）
        const uploadedImageKeys = [];
        const files = fileInput.files;

        if (files.length > 0) {
          updateStatus(`⏳ 准备上传 ${files.length} 张图片...`, 'info');
          
          for (let i = 0; i < files.length; i++) {
            const file = files[i];
            const fileNumber = i + 1;
            
            updateStatus(`[${fileNumber}/${files.length}] 正在获取图片 "${file.name}" 的上传授权...`, 'info');
            
            try {
              // 使用之前定义的 uploadFile 函数上传单个文件
              const result = await uploadFile(file);
              uploadedImageKeys.push(result.fileKey);
              updateStatus(`[${fileNumber}/${files.length}] 图片 "${file.name}" 上传成功!`, 'info');
            } catch (error) {
              console.error('图片上传失败:', error);
              throw new Error(`第 ${fileNumber} 张图片上传失败: ${error.message}`);
            }
          }
          
          updateStatus(`✅ 所有 ${files.length} 张图片上传完成!`, 'info');
        } else {
          updateStatus('ℹ️ 未选择图片。', 'info');
        }

        // 4. 提交评价数据
        updateStatus('⏳ 正在提交评价信息...', 'info');
        const reviewEndpoint = `${API_BASE_URL}/api/reviews`;
        
        try {
          const reviewResponse = await fetch(reviewEndpoint, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json'
            },
            body: JSON.stringify({
              userId,
              userName: userName || null,
              restaurantName,
              restaurantLocation,
              dishName: dishName || null,
              rating: ratingInt,
              reviewText,
              imageKeys: uploadedImageKeys
            })
          });
          
          const reviewData = await reviewResponse.json();

          if (!reviewResponse.ok) {
            console.error('提交评价失败:', reviewResponse.status, reviewData);
            throw new Error(`提交评价失败 (${reviewResponse.status}): ${reviewData.error || '未知错误'}`);
          }

          updateStatus(`🎉 评价提交成功！评价ID: ${reviewData.id}. ${reviewData.message || ''}`, 'success');
          // 清空表单
          document.getElementById('userId').value = '';
          document.getElementById('userName').value = '';
          document.getElementById('restaurantName').value = '';
          document.getElementById('restaurantLocation').value = '';
          document.getElementById('dishName').value = '';
          document.getElementById('rating').value = '';
          document.getElementById('reviewText').value = '';
          fileInput.value = '';
          imagePreviewContainer.innerHTML = '';
        } catch (error) {
          console.error('提交评价失败:', error);
          throw new Error(`提交评价失败: ${error.message}`);
        }
      } catch (error) {
        console.error('💥 操作过程中发生错误:', error);
        updateStatus(`❌ 操作失败: ${error.message}`, 'error');
      } finally {
        // 无论成功或失败，最后都重新启用按钮
        submitBtn.disabled = false;
      }
    });
  </script>
</body>
</html>